package ray.shader;

import ray.Light;
import ray.math.Color;
import ray.math.Point3;
import ray.math.Ray;
import ray.math.Vector3;

/**
 * A Phong material. Uses the Modified Blinn-Phong model which is energy
 * preserving and reciprocal.
 *
 * @author ags
 */
public class Phong implements Shader {
	
	/** The color of the diffuse reflection. */
	protected final Color diffuseColor = new Color(1, 1, 1);
	public void setDiffuseColor(Color diffuseColor) { this.diffuseColor.set(diffuseColor); }
	
	/** The color of the specular reflection. */
	protected final Color specularColor = new Color(1, 1, 1);
	public void setSpecularColor(Color specularColor) { this.specularColor.set(specularColor); }
	
	/** The exponent controlling the sharpness of the specular reflection. */
	protected double exponent = 1.0;
	public void setExponent(double exponent) { this.exponent = exponent; }
	
	public Phong() { }
	
	/**
	 * @see Object#toString()
	 */
	public String toString() {
		return "phong " + diffuseColor + " " + specularColor + " " + exponent + " end";
	}
	
	// Note this function is not called
	public Color getColor(){
		return diffuseColor;
	}
	
	public Color shade(Ray ray,Point3 point,Vector3 normal,Light light){
		Vector3 v = new Vector3();
		Vector3 l = new Vector3();
		Vector3 h;
		
		l.sub(light.position,point);
		l.normalize();
		
		v.scaleAdd(-1, ray.direction);
		v.normalize();
		
		h = new Vector3(l.x,l.y,l.z);
		h.add(v);
		h.normalize();
		
		double cosAlpha = normal.dot(l);
		double cosTheta = normal.dot(h);
		
		Color lightDiffuse = new Color();
		Color lightSpecular = new Color();
		
		lightDiffuse.scaleAdd(Math.max(0.0,cosAlpha), light.intensity);
		lightSpecular.scaleAdd(Math.pow(Math.max(0.0, cosTheta),exponent), light.intensity);
		
		Color diffuse = new Color();
		Color specular = new Color();
		
		diffuse.set(diffuseColor);
		diffuse.scale(lightDiffuse);
		
		specular.set(specularColor);
		specular.scale(lightSpecular);
		
		Color shade = new Color();
		shade.set(diffuse);
		shade.add(specular);
		
		return shade;
	}
}
